package com.jikeshijian.concurrent;

/**
 * java 并发编程的奇异bug 很多都是线程的切换
 * <p>
 * <p>
 * <p>
 * 并发编程的主要 三大特性 bug 源头:
 * 可见性 : 就是变量或是对象对所有的线程都是可见的
 * 原子性 : 就是变量在被修改的时候只能被一个线程锁修改
 * 有序性 : 就是代码不会指令重排造成, 执行顺序的错误
 * <p>
 * 造成上面的原因主要
 * 可见性就是cpu缓存和线程内存区域,造成了可见性的问题
 * 原子性就是线程间的切换带来的原子性的问题
 * 有序性就是cpu的指令重排造成的执行顺序错误
 * java 熟悉内存模型是解决并发问题最快的解决方式
 * volatile 关键字修饰的关键字就是被所有线程内存可见,关键字就是在写的操作的时候会生成一个屏蔽的执行将本线程中的变量信息同步到主内中当到啦读的时候就是会生成另外的一个指令将变量从主内存中写到变量内存中
 * ,这个关键字声明的关键字读写操作都是在内存中进行操作的,不会经过cpu缓存区
 *
 * @author yihang.xu
 */
public class Test {
    private volatile static long count = 0;

    private synchronized void add10K() {
        int idx = 0;
        while (idx++ < 10000) {
            count += 1;
        }
    }

    public static long calc() throws InterruptedException {
        final Test test = new Test();
        // 创建两个线程，执行 add() 操作
        Thread th1 = new Thread(() -> {
            test.add10K();
        });
        Thread th2 = new Thread(() -> {
            test.add10K();
        });
        // 启动两个线程
        th1.start();
        Thread.sleep(20);
        th2.start();
        // 等待两个线程执行结束
        th1.join();
        th2.join();
        return count;
    }

    public static void main(String[] args) {
        try {
            long startTime = System.currentTimeMillis();
            long calc = calc();
            long endTime = System.currentTimeMillis();
            System.out.println(endTime - startTime + "时间");

            System.out.println(calc);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
    }

    /**
     * 指令重排造成这个Singleton 对象创建的时候有可能出现问题
     *
     * @author yihang.xu
     */

    class Singleton {
        Singleton instance;

        Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }

    // 以下代码来源于【参考 1】
    class VolatileExample {
        int var = 0;
        int x = 0;
        volatile boolean v = false;

        public void writer() {
            x = 42;
            v = true;
        }

        public void reader() {
            if (v == true) {
                // 这里 x 会是多少呢？
            }

            synchronized (this) { // 此处自动加锁
                // x 是共享变量, 初始值 =10
                if (this.x < 12) {
                    this.x = 12;
                }
            } // 此处自动解锁

        }

        public void getSatrt() {
            Thread B = new Thread(() -> {
                // 主线程调用 B.start() 之前
                // 所有对共享变量的修改，此处皆可见
                // 此例中，var==77
            });
            // 此处对共享变量 var 修改
            var = 77;
            // 主线程启动子线程
            B.start();

        }

        public void getJoin() throws InterruptedException {
            Thread B = new Thread(() -> {
                // 此处对共享变量 var 修改
                var = 66;
            });
            // 例如此处对共享变量修改，
            // 则这个修改结果对线程 B 可见
            // 主线程启动子线程
            B.start();
            B.join();
            // 子线程所有对共享变量的修改
            // 在主线程调用 B.join() 之后皆可见
            // 此例中，var==66

        }


    }

    class FinalFieldExample {

        int y;
        // 以下代码来源于【参考 1】
        final int x;

        // 错误的构造函数
        public FinalFieldExample() {
            x = 3;
            y = 4;
            // 此处就是讲 this 逸出，
            //global.obj = this;
        }

    }


}
